/*
 * Copyright (C) 2005 - 2013 MaNGOS <http://www.getmangos.com/>
 *
 * Copyright (C) 2008 - 2013 Trinity <http://www.trinitycore.org/>
 *
 * Copyright (C) 2010 - 2013 ArkCORE <http://www.arkania.net/>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include "gamePCH.h"
#include "Common.h"
#include "WorldPacket.h"
#include "Opcodes.h"
#include "Log.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "Player.h"
#include "Unit.h"
#include "Spell.h"
#include "SpellAuraEffects.h"
#include "DynamicObject.h"
#include "ObjectAccessor.h"
#include "Util.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "ScriptMgr.h"
#include "SpellScript.h"

AuraApplication::AuraApplication (Unit * target, Unit * caster, Aura * aura, uint8 effMask) :
        m_target(target), m_base(aura), m_slot(MAX_AURAS), m_flags(AFLAG_NONE), m_effectsToApply(effMask), m_removeMode(AURA_REMOVE_NONE), m_needClientUpdate(false)
{
    ASSERT(GetTarget() && GetBase());

    if (GetBase()->IsVisible())
    {
        // Try find slot for aura
        uint8 slot = MAX_AURAS;
        // Lookup for auras already applied from spell
        if (AuraApplication * foundAura = GetTarget()->GetAuraApplication(GetBase()->GetId(), GetBase()->GetCasterGUID(), GetBase()->GetCastItemGUID()))
        {
            // allow use single slot only by auras from same caster
            slot = foundAura->GetSlot();
        }
        else
        {
            Unit::VisibleAuraMap const * visibleAuras = GetTarget()->GetVisibleAuras();
            // lookup for free slots in units visibleAuras
            Unit::VisibleAuraMap::const_iterator itr = visibleAuras->find(0);
            for (uint32 freeSlot = 0; freeSlot < MAX_AURAS; ++itr, ++freeSlot)
            {
                if (itr == visibleAuras->end() || itr->first != freeSlot)
                {
                    slot = freeSlot;
                    break;
                }
            }
        }

        // Register Visible Aura
        if (slot < MAX_AURAS)
        {
            m_slot = slot;
            GetTarget()->SetVisibleAura(slot, this);
            SetNeedClientUpdate();
            sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Aura: %u Effect: %d put to unit visible auras slot: %u", GetBase()->GetId(), GetEffectMask(), slot);
        }
        else
            sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Aura: %u Effect: %d could not find empty unit visible slot", GetBase()->GetId(), GetEffectMask());

        if ((target->HasAura(89489) || target->HasAura(89488)) && GetBase()->GetId() == 89485)          // strength of soul
            caster->CastSpell(caster, 96266, true);
    }

    _InitFlags(caster, effMask);
}

void AuraApplication::_Remove ()
{
    uint8 slot = GetSlot();

    if (slot >= MAX_AURAS)
        return;

    if (AuraApplication * foundAura = m_target->GetAuraApplication(GetBase()->GetId(), GetBase()->GetCasterGUID(), GetBase()->GetCastItemGUID()))
    {
        // Reuse visible aura slot by aura which is still applied - prevent storing dead pointers
        if (slot == foundAura->GetSlot())
        {
            if (GetTarget()->GetVisibleAura(slot) == this)
            {
                GetTarget()->SetVisibleAura(slot, foundAura);
                foundAura->SetNeedClientUpdate();
            }
            // set not valid slot for aura - prevent removing other visible aura
            slot = MAX_AURAS;
        }
    }

    // update for out of range group members
    if (slot < MAX_AURAS)
    {
        GetTarget()->RemoveVisibleAura(slot);
        ClientUpdate(true);
    }
}

void AuraApplication::_InitFlags (Unit * caster, uint8 effMask)
{
    // mark as selfcasted if needed
    m_flags |= (GetBase()->GetCasterGUID() == GetTarget()->GetGUID()) ? AFLAG_CASTER : AFLAG_NONE;

    // aura is casted by self or an enemy
    // one negative effect and we know aura is negative
    if (IsSelfcasted() || !caster || !caster->IsFriendlyTo(GetTarget()))
    {
        bool negativeFound = false;
        for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
        {
            if (((1 << i) & effMask) && !IsPositiveEffect(GetBase()->GetId(), i))
            {
                negativeFound = true;
                break;
            }
        }
        m_flags |= negativeFound ? AFLAG_NEGATIVE : AFLAG_POSITIVE;
    }
    // aura is casted by friend
    // one positive effect and we know aura is positive
    else
    {
        bool positiveFound = false;
        for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
        {
            if (((1 << i) & effMask) && IsPositiveEffect(GetBase()->GetId(), i))
            {
                positiveFound = true;
                break;
            }
        }
        m_flags |= positiveFound ? AFLAG_POSITIVE : AFLAG_NEGATIVE;
    }
}

void AuraApplication::_HandleEffect (uint8 effIndex, bool apply)
{
    AuraEffect * aurEff = GetBase()->GetEffect(effIndex);
    ASSERT(aurEff);
    ASSERT(HasEffect(effIndex) == (!apply));
    ASSERT((1<<effIndex) & m_effectsToApply);
    sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "AuraApplication::_HandleEffect: %u, apply: %u: amount: %u", aurEff->GetAuraType(), apply, aurEff->GetAmount());

    if (apply)
    {
        m_flags |= 1 << effIndex;
        GetTarget()->_RegisterAuraEffect(aurEff, true);
        aurEff->HandleEffect(this, AURA_EFFECT_HANDLE_REAL, true);
    }
    else
    {
        m_flags &= ~(1 << effIndex);

        // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
        GetTarget()->_RegisterAuraEffect(aurEff, false);
        aurEff->HandleEffect(this, AURA_EFFECT_HANDLE_REAL, false);

        // Remove all triggered by aura spells vs unlimited duration
        aurEff->CleanupTriggeredSpells(GetTarget());
    }
    SetNeedClientUpdate();
}

void AuraApplication::ClientUpdate (bool remove)
{
    m_needClientUpdate = false;

    WorldPacket data(SMSG_AURA_UPDATE);
    data.append(GetTarget()->GetPackGUID());
    data << uint8(m_slot);

    if (remove)
    {
        ASSERT(!m_target->GetVisibleAura(m_slot));
        data << uint32(0);
        sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Aura %u removed slot %u", GetBase()->GetId(), m_slot);
        m_target->SendMessageToSet(&data, true);
        return;
    }
    ASSERT(m_target->GetVisibleAura(m_slot));

    Aura const * aura = GetBase();
    data << uint32(aura->GetId());
    uint32 flags = m_flags;
    if (aura->GetMaxDuration() > 0 && !(aura->GetSpellProto()->AttributesEx5 & SPELL_ATTR5_HIDE_DURATION))
        flags |= AFLAG_DURATION;
    if (!aura->IsPassive())
        flags |= AFLAG_ANY_EFFECT_AMOUNT_SENT;
    data << uint8(flags);
    data << uint8(aura->GetCasterLevel());
    data << uint8(aura->GetStackAmount() > 1 ? aura->GetStackAmount() : (aura->GetCharges()) ? aura->GetCharges() : 1);

    if (!(flags & AFLAG_CASTER))
        data.appendPackGUID(aura->GetCasterGUID());

    if (flags & AFLAG_DURATION)
    {
        data << uint32(aura->GetMaxDuration());
        data << uint32(aura->GetDuration());
    }

    if (flags & AFLAG_ANY_EFFECT_AMOUNT_SENT)
    {
        for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
        {
            if (flags & 1 << i)
                data << uint32(aura->GetEffect(i)->GetAmount());
        }
    }

    m_target->SendMessageToSet(&data, true);
}

Aura * Aura::TryCreate (SpellEntry const* spellproto, uint8 tryEffMask, WorldObject * owner, Unit * caster, int32 *baseAmount, Item * castItem, uint64 casterGUID)
{
    ASSERT(spellproto);
    ASSERT(owner);
    ASSERT(caster || casterGUID);
    ASSERT(tryEffMask <= MAX_EFFECT_MASK);
    uint8 effMask = 0;
    switch (owner->GetTypeId())
    {
    case TYPEID_UNIT:
    case TYPEID_PLAYER:
        for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
        {
            if (IsUnitOwnedAuraEffect(spellproto->Effect[i]))
                effMask |= 1 << i;
        }
        break;
    case TYPEID_DYNAMICOBJECT:
        for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
        {
            if (spellproto->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA)
                effMask |= 1 << i;
        }
        break;
    default:
        break;
    }
    if (uint8 realMask = effMask & tryEffMask)
        return Create(spellproto, realMask, owner, caster, baseAmount, castItem, casterGUID);
    return NULL;
}

Aura * Aura::TryCreate (SpellEntry const* spellproto, WorldObject * owner, Unit * caster, int32 *baseAmount, Item * castItem, uint64 casterGUID)
{
    ASSERT(spellproto);
    ASSERT(owner);
    ASSERT(caster || casterGUID);
    uint8 effMask = 0;
    switch (owner->GetTypeId())
    {
    case TYPEID_UNIT:
    case TYPEID_PLAYER:
        for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
        {
            if (IsUnitOwnedAuraEffect(spellproto->Effect[i]))
                effMask |= 1 << i;
        }
        break;
    case TYPEID_DYNAMICOBJECT:
        for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
        {
            if (spellproto->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA)
                effMask |= 1 << i;
        }
        break;
    default:
        break;
    }
    if (effMask)
        return Create(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID);
    return NULL;
}

Aura * Aura::Create (SpellEntry const* spellproto, uint8 effMask, WorldObject * owner, Unit * caster, int32 *baseAmount, Item * castItem, uint64 casterGUID)
{
    ASSERT(effMask);
    ASSERT(spellproto);
    ASSERT(owner);
    ASSERT(caster || casterGUID);
    ASSERT(effMask <= MAX_EFFECT_MASK);
    // try to get caster of aura
    if (casterGUID)
    {
        if (owner->GetGUID() == casterGUID)
            caster = (Unit *) owner;
        else
            caster = ObjectAccessor::GetUnit(*owner, casterGUID);
    }
    else
    {
        casterGUID = caster->GetGUID();
    }
    // check if aura can be owned by owner
    if (owner->isType(TYPEMASK_UNIT))
    {
        if (!owner->IsInWorld() || ((Unit*) owner)->IsDuringRemoveFromWorld())
        {
            // owner not in world so
            // don't allow to own not self casted single target auras
            if (casterGUID != owner->GetGUID() && IsSingleTargetSpell(spellproto))
                return NULL;
        }
    }
    Aura * aura = NULL;
    switch (owner->GetTypeId())
    {
    case TYPEID_UNIT:
    case TYPEID_PLAYER:
        aura = new UnitAura(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID);
        break;
    case TYPEID_DYNAMICOBJECT:
        aura = new DynObjAura(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID);
        break;
    default:
        ASSERT(false)
        ;
        return NULL;
    }
    // aura can be removed in Unit::_AddAura call
    if (aura->IsRemoved())
        return NULL;
    return aura;
}

Aura::Aura (SpellEntry const* spellproto, uint8 effMask, WorldObject * owner, Unit * caster, int32 *baseAmount, Item * castItem, uint64 casterGUID) :
        m_spellProto(spellproto), m_casterGuid(casterGUID ? casterGUID : caster->GetGUID()), m_castItemGuid(castItem ? castItem->GetGUID() : 0), m_applyTime(time(NULL)), m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0), m_casterLevel(caster ? caster->getLevel() : m_spellProto->spellLevel), m_procCharges(0), m_stackAmount(1), m_isRemoved(false), m_isSingleTarget(false)
{
    if (m_spellProto->manaPerSecond)
        m_timeCla = 1 * IN_MILLISECONDS;

    Player* modOwner = NULL;

    if (caster)
    {
        modOwner = caster->GetSpellModOwner();
        m_maxDuration = caster->CalcSpellDuration(m_spellProto);
    }
    else
        m_maxDuration = GetSpellDuration(m_spellProto);

    if (IsPassive() && m_spellProto->DurationIndex == 0)
        m_maxDuration = -1;

    if (!IsPermanent() && modOwner)
        modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, m_maxDuration);

    m_duration = m_maxDuration;

    m_procCharges = m_spellProto->procCharges;
    if (modOwner)
        modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, m_procCharges);
}
void Aura::_InitEffects (uint8 effMask, Unit * caster, int32 *baseAmount)
{
    // shouldn't be in constructor - functions in AuraEffect::AuraEffect use polymorphism
    for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
    {
        if (effMask & (uint8(1) << i))
            m_effects[i] = new AuraEffect(this, i, baseAmount ? baseAmount + i : NULL, caster);
        else
            m_effects[i] = NULL;
    }

    // Mixology
    if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_POTION && caster /*&& caster->IsPlayer()*/
    && caster->HasAura(53042))
    {
        if (sSpellMgr->IsSpellMemberOfSpellGroup(GetSpellProto()->Id, SPELL_GROUP_ELIXIR_BATTLE) || sSpellMgr->IsSpellMemberOfSpellGroup(GetSpellProto()->Id, SPELL_GROUP_ELIXIR_GUARDIAN))
        {
            m_maxDuration *= 2;
            m_duration = m_maxDuration;
            for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
            {
                if (effMask & (uint8(1) << i))
                    m_effects[i]->SetAmount((int32) (m_effects[i]->GetAmount() * 1.3f));
            }
        }
    }
}

Aura::~Aura ()
{
    // unload scripts
    while (!m_loadedScripts.empty())
    {
        std::list<AuraScript *>::iterator itr = m_loadedScripts.begin();
        (*itr)->_Unload();
        delete (*itr);
        m_loadedScripts.erase(itr);
    }

    // free effects memory
    for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
        delete m_effects[i];

    ASSERT(m_applications.empty());
    _DeleteRemovedApplications();
}

Unit* Aura::GetCaster () const
{
    if (GetOwner()->GetGUID() == GetCasterGUID())
        return GetUnitOwner();
    if (AuraApplication const * aurApp = GetApplicationOfTarget(GetCasterGUID()))
        return aurApp->GetTarget();

    return ObjectAccessor::GetUnit(*GetOwner(), GetCasterGUID());
}

AuraObjectType Aura::GetType () const
{
    return (m_owner->GetTypeId() == TYPEID_DYNAMICOBJECT) ? DYNOBJ_AURA_TYPE : UNIT_AURA_TYPE;
}

void Aura::_ApplyForTarget (Unit * target, Unit * caster, AuraApplication * auraApp)
{
    ASSERT(target);
    ASSERT(auraApp);
    // aura mustn't be already applied
    ASSERT (m_applications.find(target->GetGUID()) == m_applications.end());

    m_applications[target->GetGUID()] = auraApp;

    // set infinity cooldown state for spells
    if (caster && caster->GetTypeId() == TYPEID_PLAYER)
    {
        if (m_spellProto->Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE)
        {
            Item* castItem = m_castItemGuid ? caster->ToPlayer()->GetItemByGuid(m_castItemGuid) : NULL;
            caster->ToPlayer()->AddSpellAndCategoryCooldowns(m_spellProto, castItem ? castItem->GetEntry() : 0, NULL, true);
        }
    }
}

void Aura::_UnapplyForTarget (Unit * target, Unit * caster, AuraApplication * auraApp)
{
    ASSERT(target);
    ASSERT(auraApp->GetRemoveMode());
    ASSERT(auraApp);

    ApplicationMap::iterator itr = m_applications.find(target->GetGUID());
    // TODO: Figure out why this happens.
    if (itr == m_applications.end())
    {
        sLog->outError("Aura::_UnapplyForTarget, target:%u, caster:%u, spell:%u was not found in owners application map!", target->GetGUIDLow(), caster->GetGUIDLow(), auraApp->GetBase()->GetSpellProto()->Id);
    }
    else
        m_applications.erase(itr);

    // aura has to be already applied
    //ASSERT(itr->second == auraApp);
    m_removedApplications.push_back(auraApp);

    // reset cooldown state for spells
    if (caster && caster->GetTypeId() == TYPEID_PLAYER)
    {
        if (GetSpellProto()->Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE)
            // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
            caster->ToPlayer()->SendCooldownEvent(GetSpellProto());
    }
}

// removes aura from all targets
// and marks aura as removed
void Aura::_Remove (AuraRemoveMode removeMode)
{
    ASSERT (!m_isRemoved);
    m_isRemoved = true;
    ApplicationMap::iterator appItr = m_applications.begin();
    for (appItr = m_applications.begin(); appItr != m_applications.end();)
    {
        AuraApplication * aurApp = appItr->second;
        Unit * target = aurApp->GetTarget();
        target->_UnapplyAura(aurApp, removeMode);
        appItr = m_applications.begin();
    }
}

void Aura::UpdateTargetMap (Unit * caster, bool apply)
{
    if (IsRemoved())
        return;

    m_updateTargetMapInterval = UPDATE_TARGET_MAP_INTERVAL;

    // fill up to date target list
    //       target, effMask
    std::map<Unit *, uint8> targets;

    FillTargetMap(targets, caster);

    UnitList targetsToRemove;

    // mark all auras as ready to remove
    for (ApplicationMap::iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter)
    {
        std::map<Unit *, uint8>::iterator existing = targets.find(appIter->second->GetTarget());
        // not found in current area - remove the aura
        if (existing == targets.end())
            targetsToRemove.push_back(appIter->second->GetTarget());
        else
        {
            // needs readding - remove now, will be applied in next update cycle
            // (dbcs do not have auras which apply on same type of targets but have different radius, so this is not really needed)
            if (appIter->second->GetEffectMask() != existing->second || !CanBeAppliedOn(existing->first))
                targetsToRemove.push_back(appIter->second->GetTarget());
            // nothing todo - aura already applied
            // remove from auras to register list
            targets.erase(existing);
        }
    }

    // register auras for units
    for (std::map<Unit *, uint8>::iterator itr = targets.begin(); itr != targets.end();)
    {
        // aura mustn't be already applied on target
        if (AuraApplication * aurApp = GetApplicationOfTarget(itr->first->GetGUID()))
        {
            // the core created 2 different units with same guid
            // this is a major failure, which i can't fix right now
            // let's remove one unit from aura list
            // this may cause area aura "bouncing" between 2 units after each update
            // but because we know the reason of a crash we can remove the assertion for now
            if (aurApp->GetTarget() != itr->first)
            {
                // remove from auras to register list
                targets.erase(itr++);
                continue;
            }
        }

        bool addUnit = true;
        // check target immunities
        if (itr->first->IsImmunedToSpell(GetSpellProto()) || !CanBeAppliedOn(itr->first))
            addUnit = false;

        if (addUnit)
        {
            // persistent area aura does not hit flying targets
            if (GetType() == DYNOBJ_AURA_TYPE)
            {
                if (itr->first->isInFlight())
                    addUnit = false;
            }
            // unit auras can not stack with each other
            else          // (GetType() == UNIT_AURA_TYPE)
            {
                // Allow to remove by stack when aura is going to be applied on owner
                if (itr->first != GetOwner())
                {
                    // check if not stacking aura already on target
                    // this one prevents unwanted usefull buff loss because of stacking and prevents overriding auras periodicaly by 2 near area aura owners
                    for (Unit::AuraApplicationMap::iterator iter = itr->first->GetAppliedAuras().begin(); iter != itr->first->GetAppliedAuras().end(); ++iter)
                    {
                        Aura const * aura = iter->second->GetBase();
                        if (!sSpellMgr->CanAurasStack(this, aura, aura->GetCasterGUID() == GetCasterGUID()))
                        {
                            addUnit = false;
                            break;
                        }
                    }
                }
            }
        }
        if (!addUnit)
            targets.erase(itr++);
        else
        {
            // owner has to be in world, or effect has to be applied to self
            ASSERT((!GetOwner()->IsInWorld() && GetOwner() == itr->first) || GetOwner()->IsInMap(itr->first));
            itr->first->_CreateAuraApplication(this, itr->second);
            ++itr;
        }
    }

    // remove auras from units no longer needing them
    for (UnitList::iterator itr = targetsToRemove.begin(); itr != targetsToRemove.end(); ++itr)
        if (AuraApplication * aurApp = GetApplicationOfTarget((*itr)->GetGUID()))
            (*itr)->_UnapplyAura(aurApp, AURA_REMOVE_BY_DEFAULT);

    if (!apply)
        return;

    // apply aura effects for units
    for (std::map<Unit *, uint8>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
    {
        if (AuraApplication * aurApp = GetApplicationOfTarget(itr->first->GetGUID()))
        {
            // owner has to be in world, or effect has to be applied to self
            ASSERT((!GetOwner()->IsInWorld() && GetOwner() == itr->first) || GetOwner()->IsInMap(itr->first));
            itr->first->_ApplyAura(aurApp, itr->second);
        }
    }
}

// targets have to be registered and not have effect applied yet to use this function
void Aura::_ApplyEffectForTargets (uint8 effIndex)
{
    //Unit * caster = GetCaster();
    // prepare list of aura targets
    UnitList targetList;
    for (ApplicationMap::iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter)
    {
        if ((appIter->second->GetEffectsToApply() & (1 << effIndex)) && !appIter->second->HasEffect(effIndex))
            targetList.push_back(appIter->second->GetTarget());
    }

    // apply effect to targets
    for (UnitList::iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
    {
        if (GetApplicationOfTarget((*itr)->GetGUID()))
        {
            // owner has to be in world, or effect has to be applied to self
            ASSERT((!GetOwner()->IsInWorld() && GetOwner() == *itr) || GetOwner()->IsInMap(*itr));
            (*itr)->_ApplyAuraEffect(this, effIndex);
        }
    }
}
void Aura::UpdateOwner (uint32 diff, WorldObject * owner)
{
    ASSERT(owner == m_owner);

    Unit * caster = GetCaster();
    // Apply spellmods for channeled auras
    // used for example when triggered spell of spell:10 is modded
    Spell * modSpell = NULL;
    Player * modOwner = NULL;
    if (caster)
    {
        modOwner = caster->GetSpellModOwner();
        if (modOwner)
        {
            modSpell = modOwner->FindCurrentSpellBySpellId(GetId());
            if (modSpell)
                modOwner->SetSpellModTakingSpell(modSpell, true);
        }
    }

    Update(diff, caster);

    if (m_updateTargetMapInterval <= int32(diff))
        UpdateTargetMap(caster);
    else
        m_updateTargetMapInterval -= diff;

    // update aura effects
    for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
        if (m_effects[i])
            m_effects[i]->Update(diff, caster);

    // remove spellmods after effects update
    if (modSpell)
        modOwner->SetSpellModTakingSpell(modSpell, false);

    _DeleteRemovedApplications();
}

void Aura::Update (uint32 diff, Unit * caster)
{
    if (m_duration > 0)
    {
        m_duration -= diff;
        if (m_duration < 0)
            m_duration = 0;

        // handle manaPerSecond/manaPerSecondPerLevel
        if (m_timeCla)
        {
            if (m_timeCla > int32(diff))
                m_timeCla -= diff;
            else if (caster)
            {
                if (int32 manaPerSecond = m_spellProto->manaPerSecond)
                {
                    m_timeCla += 1000 - diff;

                    Powers powertype = Powers(m_spellProto->powerType);
                    if (powertype == POWER_HEALTH)
                    {
                        if (int32(caster->GetHealth()) > manaPerSecond)
                            caster->ModifyHealth(-manaPerSecond);
                        else
                        {
                            Remove();
                            return;
                        }
                    }
                    else
                    {
                        if (int32(caster->GetPower(powertype)) >= manaPerSecond)
                            caster->ModifyPower(powertype, -manaPerSecond);
                        else
                        {
                            Remove();
                            return;
                        }
                    }
                }
            }
        }
    }
}

void Aura::SetDuration (int32 duration, bool withMods)
{
    if (withMods)
    {
        if (Unit * caster = GetCaster())
            if (Player * modOwner = caster->GetSpellModOwner())
                modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, duration);
    }
    m_duration = duration;
    SetNeedClientUpdateForTargets();
}

void Aura::RefreshDuration ()
{
    SetDuration(GetMaxDuration());
    for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
        if (m_effects[i])
            m_effects[i]->ResetPeriodic();

    if (m_spellProto->manaPerSecond)
        m_timeCla = 1 * IN_MILLISECONDS;
}

void Aura::SetCharges (uint8 charges)
{
    if (m_procCharges == charges)
        return;
    m_procCharges = charges;
    SetNeedClientUpdateForTargets();
}

bool Aura::DropCharge ()
{
    if (m_procCharges)          //auras without charges always have charge = 0
    {
        if (--m_procCharges)          // Send charge change
            SetNeedClientUpdateForTargets();
        else          // Last charge dropped
        {
            Remove(AURA_REMOVE_BY_EXPIRE);
            return true;
        }
    }
    return false;
}

void Aura::SetStackAmount (uint8 stackAmount, bool /*applied*/)
{
    if (stackAmount != m_stackAmount)
    {
        m_stackAmount = stackAmount;
        RecalculateAmountOfEffects();
    }
    SetNeedClientUpdateForTargets();
}

bool Aura::ModStackAmount (int32 num)
{
    // Can`t mod
    if (!m_spellProto->StackAmount || !GetStackAmount())
        return true;

    // Modify stack but limit it
    int32 stackAmount = m_stackAmount + num;
    if (stackAmount > int32(m_spellProto->StackAmount))
        stackAmount = m_spellProto->StackAmount;
    else if (stackAmount <= 0)          // Last aura from stack removed
    {
        m_stackAmount = 0;
        return true;          // need remove aura
    }
    bool refresh = stackAmount >= GetStackAmount();

    // Update stack amount
    SetStackAmount(stackAmount);

    if (refresh)
        RefreshDuration();
    SetNeedClientUpdateForTargets();

    return false;
}

bool Aura::IsPassive () const
{
    return IsPassiveSpell(GetSpellProto());
}

bool Aura::IsDeathPersistent () const
{
    return IsDeathPersistentSpell(GetSpellProto());
}

bool Aura::CanBeSaved () const
{
    if (IsPassive())
        return false;

    if (GetCasterGUID() != GetOwner()->GetGUID())
        if (IsSingleTargetSpell(GetSpellProto()))
            return false;

    // Can't be saved - aura handler relies on calculated amount and changes it
    if (HasEffectType(SPELL_AURA_CONVERT_RUNE))
        return false;

    // No point in saving this, since the stable dialog can't be open on aura load anyway.
    if (HasEffectType(SPELL_AURA_OPEN_STABLE))
        return false;

    return true;
}

bool Aura::IsVisible () const
{
    return !IsPassive() || HasAreaAuraEffect(GetSpellProto()) || HasEffectType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
}

void Aura::UnregisterSingleTarget ()
{
    ASSERT(m_isSingleTarget);
    Unit * caster = GetCaster();
    // TODO: find a better way to do this.
    if (!caster)
        caster = ObjectAccessor::GetObjectInOrOutOfWorld(GetCasterGUID(), (Unit*) NULL);
    ASSERT(caster);
    caster->GetSingleCastAuras().remove(this);
    SetIsSingleTarget(false);
}

void Aura::SetLoadedState (int32 maxduration, int32 duration, int32 charges, uint8 stackamount, uint8 recalculateMask, int32 * amount)
{
    m_maxDuration = maxduration;
    m_duration = duration;
    m_procCharges = charges;
    m_stackAmount = stackamount;
    Unit * caster = GetCaster();
    for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
        if (m_effects[i])
        {
            m_effects[i]->SetAmount(amount[i]);
            m_effects[i]->SetCanBeRecalculated(recalculateMask & (1 << i));
            m_effects[i]->CalculatePeriodic(caster);
            m_effects[i]->CalculateSpellMod();
            m_effects[i]->RecalculateAmount(caster);
        }
}

bool Aura::HasEffectType (AuraType type) const
{
    for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
    {
        if (m_effects[i] && m_effects[i]->GetAuraType() == type)
            return true;
    }
    return false;
}

void Aura::RecalculateAmountOfEffects ()
{
    ASSERT (!IsRemoved());
    Unit * caster = GetCaster();
    for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
        if (m_effects[i])
            m_effects[i]->RecalculateAmount(caster);
}

void Aura::HandleAllEffects (AuraApplication const * aurApp, uint8 mode, bool apply)
{
    ASSERT (!IsRemoved());
    for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
        if (m_effects[i] && !IsRemoved())
            m_effects[i]->HandleEffect(aurApp, mode, apply);
}

void Aura::SetNeedClientUpdateForTargets () const
{
    for (ApplicationMap::const_iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter)
        appIter->second->SetNeedClientUpdate();
}

// trigger effects on real aura apply/remove
void Aura::HandleAuraSpecificMods (AuraApplication const* aurApp, Unit* caster, bool apply, bool onReapply)
{
    Unit * target = aurApp->GetTarget();
    AuraRemoveMode removeMode = aurApp->GetRemoveMode();
    // spell_area table
    SpellAreaForAreaMapBounds saBounds = sSpellMgr->GetSpellAreaForAuraMapBounds(GetId());
    if (saBounds.first != saBounds.second)
    {
        uint32 zone, area;
        target->GetZoneAndAreaId(zone, area);

        for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
        {
            // some auras remove at aura remove
            if (!itr->second->IsFitToRequirements((Player*) target, zone, area))
                target->RemoveAurasDueToSpell(itr->second->spellId);
            // some auras applied at aura apply
            else if (itr->second->autocast)
            {
                if (!target->HasAura(itr->second->spellId))
                    target->CastSpell(target, itr->second->spellId, true);
            }
        }
    }

    // handle spell_linked_spell table
    if (!onReapply)
    {
        // apply linked auras
        if (apply)
        {
            if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(GetId() + SPELL_LINK_AURA))
            {
                for (std::vector<int32>::const_iterator itr = spellTriggered->begin(); itr != spellTriggered->end(); ++itr)
                {
                    if (*itr < 0)
                        target->ApplySpellImmune(GetId(), IMMUNITY_ID, -(*itr), true);
                    else if (caster)
                        caster->AddAura(*itr, target);
                }
            }
        }
        else
        {
            // remove linked auras
            if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(-(int32) GetId()))
            {
                for (std::vector<int32>::const_iterator itr = spellTriggered->begin(); itr != spellTriggered->end(); ++itr)
                {
                    if (*itr < 0)
                        target->RemoveAurasDueToSpell(-(*itr));
                    else if (removeMode != AURA_REMOVE_BY_DEATH)
                        target->CastSpell(target, *itr, true, NULL, NULL, GetCasterGUID());
                }
            }
            if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(GetId() + SPELL_LINK_AURA))
            {
                for (std::vector<int32>::const_iterator itr = spellTriggered->begin(); itr != spellTriggered->end(); ++itr)
                {
                    if (*itr < 0)
                        target->ApplySpellImmune(GetId(), IMMUNITY_ID, -(*itr), false);
                    else
                        target->RemoveAura(*itr, GetCasterGUID(), 0, removeMode);
                }
            }
        }
    }
    else if (apply)
    {
        // modify stack amount of linked auras
        if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(GetId() + SPELL_LINK_AURA))
        {
            for (std::vector<int32>::const_iterator itr = spellTriggered->begin(); itr != spellTriggered->end(); ++itr)
                if (*itr > 0)
                    if (Aura* triggeredAura = target->GetAura(*itr, GetCasterGUID()))
                        triggeredAura->ModStackAmount(GetStackAmount() - triggeredAura->GetStackAmount());
        }
    }

    // mods at aura apply
    if (apply)
    {
        // Apply linked auras (On first aura apply)
        if (sSpellMgr->GetSpellCustomAttr(GetId()) & SPELL_ATTR0_CU_LINK_AURA)
        {
            if (const std::vector<int32> *spell_triggered = sSpellMgr->GetSpellLinked(GetId() + SPELL_LINK_AURA))
                for (std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
                {
                    if (*itr < 0)
                        target->ApplySpellImmune(GetId(), IMMUNITY_ID, -(*itr), true);
                    else if (caster)
                        caster->AddAura(*itr, target);
                }
        }
        switch (GetSpellProto()->SpellFamilyName)
        {
        case SPELLFAMILY_GENERIC:
            switch (GetId())
            {
            case 32474:          // Buffeting Winds of Susurrus
                if (target->GetTypeId() == TYPEID_PLAYER)
                    target->ToPlayer()->ActivateTaxiPathTo(506, GetId());
                break;
            case 33572:          // Gronn Lord's Grasp, becomes stoned
                if (GetStackAmount() >= 5 && !target->HasAura(33652))
                    target->CastSpell(target, 33652, true);
                break;
            case 50836:          //Petrifying Grip, becomes stoned
                if (GetStackAmount() >= 5 && !target->HasAura(50812))
                    target->CastSpell(target, 50812, true);
                break;
            case 60970:          // Heroic Fury (remove Intercept cooldown)
                if (target->GetTypeId() == TYPEID_PLAYER)
                    target->ToPlayer()->RemoveSpellCooldown(20252, true);
                break;
            }
            break;
        case SPELLFAMILY_MAGE:
            if (!caster)
                break;
            if (GetSpellProto()->SpellFamilyFlags[0] & 0x00000001 && GetSpellProto()->SpellFamilyFlags[2] & 0x00000008)
            {
                // Glyph of Fireball
                if (caster->HasAura(56368))
                    SetDuration(0);
            }
            else if (GetSpellProto()->SpellFamilyFlags[0] & 0x00000020 && GetSpellProto()->SpellVisual[0] == 13)
            {
                // Glyph of Frostbolt
                if (caster->HasAura(56370))
                    SetDuration(0);
            }
            // Todo: This should be moved to similar function in spell::hit
            else if (GetSpellProto()->SpellFamilyFlags[0] & 0x01000000)
            {
                // Polymorph Sound - Sheep && Penguin
                if (GetSpellProto()->SpellIconID == 82 && GetSpellProto()->SpellVisual[0] == 12978)
                {
                    if (caster->HasAura(52648))          // Glyph of the Penguin
                        caster->CastSpell(target, 61635, true);
                    else if (caster->HasAura(57927))          // Glyph of the Monkey
                        caster->CastSpell(target, 89729, true);

                    else
                        caster->CastSpell(target, 61634, true);
                }
            }
            switch (GetId())
            {
            case 12536:          // Clearcasting
            case 12043:          // Presence of Mind
                // Arcane Potency
                if (AuraEffect const * aurEff = caster->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_MAGE, 2120, 0))
                {
                    uint32 spellId = 0;

                    switch (aurEff->GetId())
                    {
                    case 31571:
                        spellId = 57529;
                        break;
                    case 31572:
                        spellId = 57531;
                        break;
                    default:
                        sLog->outError("Aura::HandleAuraSpecificMods: Unknown rank of Arcane Potency (%d) found", aurEff->GetId());
                    }
                    if (spellId)
                        caster->CastSpell(caster, spellId, true);
                }
                break;
            case 44544:          // Fingers of Frost
            {
                // See if we already have the indicator aura. If not, create one.
                if (Aura *aur = target->GetAura(74396))
                {
                    // Aura already there. Refresh duration and set original charges
                    aur->SetCharges(2);
                    aur->RefreshDuration();
                }
                else
                    target->AddAura(74396, target);
            }
            case 83301:          // Improved Cone of Cold r1 freeze
                if (!caster->HasAura(11190))          // r1 talent
                    target->RemoveAura(83301);
            case 83302:          // Improved Cone of Cold r2 freeze
                if (!caster->HasAura(12489))          // r2 talent
                    target->RemoveAura(83302);

            default:
                break;
            }
            break;
        case SPELLFAMILY_HUNTER:
            // Animal Handler
            if (GetId() == 68361)
            {
                if (Unit* owner = target->GetOwner())
                    if (AuraEffect* auraEff = owner->GetDummyAuraEffect(SPELLFAMILY_HUNTER, 2234, 1))
                        GetEffect(0)->SetAmount(auraEff->GetAmount());
            }
            break;
        case SPELLFAMILY_WARLOCK:
            switch (GetId())
            {
            case 6358:          // Seduction
                if (!caster)
                    break;
                if (Unit *owner = caster->GetOwner())
                    if (owner->HasAura(56250))          // Glyph of Succubus
                    {
                        target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE, 0, target->GetAura(32409));          // SW:D shall not be removed.
                        target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
                        target->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
                    }
                break;
            case 48020:          // Demonic Circle
                if (target->GetTypeId() == TYPEID_PLAYER)
                    if (GameObject* obj = caster->GetGameObject(48018))
                    {
                        if (caster->IsWithinDist(obj, GetSpellMaxRange(GetSpellProto(), true)))
                        {
                            caster->NearTeleportTo(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation());
                            caster->RemoveMovementImpairingAuras();
                        }
                        if (caster->HasAura(74434))
                        {
                            caster->RemoveMovementImpairingAuras();
                            caster->CastSpell(caster,79438,true);
                            caster->CastSpell(caster,79438,true);
                        }
                    }
                break;
            }
            break;
        case SPELLFAMILY_PRIEST:
            if (!caster)
                break;
            // Devouring Plague
            if (GetId() == 2944)
            {
                // Improved Devouring Plague
                if (AuraEffect const * aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 3790, 0))
                {
                    int32 basepoints0 = aurEff->GetAmount() * GetEffect(0)->GetTotalTicks() * caster->SpellDamageBonus(target, GetSpellProto(), 0, GetEffect(0)->GetAmount(), DOT) / 100;
                    caster->CastCustomSpell(target, 63675, &basepoints0, NULL, NULL, true, NULL, GetEffect(0));
                }
            }
            // Mind fly
            if (GetId() == 15407)
            {
                // Pain and Suffering: Rank 1
                if (Aura* pain = caster->GetAura(47580))
                {
                    if (Aura* swp = target->GetAura(589))
                    {
                        if (roll_chance_i(30))
                            swp->RefreshDuration();
                    }
                }
                // Pain and Suffering: Rank 2
                if (Aura* pain = caster->GetAura(47581))
                {
                    if (Aura* swp = target->GetAura(589))
                    {
                        if (roll_chance_i(60))
                            swp->RefreshDuration();
                    }
                }
            }
            // Renew
            if (GetId() == 139)
            {
                // Empowered Renew
                if (AuraEffect const * aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 3021, 0))
                {
                    int32 basepoints0 = aurEff->GetAmount() * GetEffect(0)->GetTotalTicks() * caster->SpellHealingBonus(target, GetSpellProto(), 0, GetEffect(0)->GetAmount(), HEAL) / 100;
                    caster->CastCustomSpell(target, 63544, &basepoints0, NULL, NULL, true, NULL, GetEffect(0));
                }
            }
            // Power Word: Shield
            if (GetId() == 17)
            {
                // Glyph of Power Word: Shield
                if (AuraEffect* glyph = caster->GetAuraEffect(55672, 0))
                {
                    // instantly heal m_amount% of the absorb-value
                    int32 heal = glyph->GetAmount() * GetEffect(0)->GetAmount() / 100;
                    caster->CastCustomSpell(GetUnitOwner(), 56160, &heal, NULL, NULL, true, 0, GetEffect(0));
                }
            }
            break;
        case SPELLFAMILY_ROGUE:
            // Sprint (skip non player casted spells by category)
            if (GetSpellProto()->SpellFamilyFlags[0] & 0x40 && GetSpellProto()->Category == 44)
                // in official maybe there is only one icon?
                if (target->HasAura(58039))          // Glyph of Blurred Speed
                    target->CastSpell(target, 61922, true);          // Sprint (waterwalk)

            // Deadly Momentum
            if (GetId() == 84590)
            {
                if (Aura* snd = target->GetAura(5171))
                    snd->RefreshDuration();
                if (Aura* rec = target->GetAura(73651))
                    rec->RefreshDuration();
            }
            break;
        case SPELLFAMILY_PALADIN:          // Speed of Light (talent)
            if (GetId() == 82327)
            {
                if (target->HasAura(85495))          // r1
                {
                    target->CastSpell(target, 85497, true);
                    target->SetSpeed(MOVE_RUN, 1.2f, true);
                }
                if (target->HasAura(85498))          // r2
                {
                    target->CastSpell(target, 85497, true);
                    target->SetSpeed(MOVE_RUN, 1.4f, true);
                }
                if (target->HasAura(85499))          // r3
                {
                    target->CastSpell(target, 85497, true);
                    target->SetSpeed(MOVE_RUN, 1.6f, true);
                }
            }
            // Sanctfied Wrath Cataclysm proc
            if (GetId() == 31884){
                if (caster->HasAura(53375) || caster->HasAura(53376) || caster->HasAura(90286)){
                    caster->CastSpell(caster, 57318, true);
                    }
                }
                if(GetId() == 85416)    // Grand Crusader                     
                {  
                    // Reset cooldown on Avanger Shield  
                    caster->ToPlayer()->RemoveSpellCooldown(31935, true);  
                }
                break;
        case SPELLFAMILY_DEATHKNIGHT:
            if (!caster)
                break;
            // Frost Fever and Blood Plague
            if (GetSpellProto()->SpellFamilyFlags[2] & 0x2)
            {
                // Can't proc on self
                if (GetCasterGUID() == target->GetGUID())
                    break;

                AuraEffect * aurEff = NULL;
                // Ebon Plaguebringer / Crypt Fever
                Unit::AuraEffectList const& TalentAuras = caster->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
                for (Unit::AuraEffectList::const_iterator itr = TalentAuras.begin(); itr != TalentAuras.end(); ++itr)
                {
                    if ((*itr)->GetMiscValue() == 7282)
                    {
                        aurEff = *itr;
                        // Ebon Plaguebringer - end search if found
                        if ((*itr)->GetSpellProto()->SpellIconID == 1766)
                            break;
                    }
                }
                if (aurEff)
                {
                    uint32 spellId = 0;
                    switch (aurEff->GetId())
                    {
                    // Ebon Plague
                    case 51161:
                        spellId = 51735;
                        break;
                    case 51160:
                        spellId = 51734;
                        break;
                    case 51099:
                        spellId = 51726;
                        break;
                        // Crypt Fever
                    case 49632:
                        spellId = 50510;
                        break;
                    case 49631:
                        spellId = 50509;
                        break;
                    case 49032:
                        spellId = 50508;
                        break;
                    default:
                        sLog->outError("Aura::HandleAuraSpecificMods: Unknown rank of Crypt Fever/Ebon Plague (%d) found", aurEff->GetId());
                    }
                    caster->CastSpell(target, spellId, true, 0, GetEffect(0));
                }
            }
            break;
        }
    }
    // mods at aura remove
    else
    {
        // Remove Linked Auras
        if (removeMode != AURA_REMOVE_BY_STACK && removeMode != AURA_REMOVE_BY_DEATH)
        {
            if (uint32 customAttr = sSpellMgr->GetSpellCustomAttr(GetId()))
            {
                if (customAttr & SPELL_ATTR0_CU_LINK_REMOVE)
                {
                    if (const std::vector<int32> *spell_triggered = sSpellMgr->GetSpellLinked(-(int32) GetId()))
                        for (std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
                        {
                            if (*itr < 0)
                                target->RemoveAurasDueToSpell(-(*itr));
                            else if (removeMode != AURA_REMOVE_BY_DEFAULT)
                                target->CastSpell(target, *itr, true, NULL, NULL, GetCasterGUID());
                        }
                }
                if (customAttr & SPELL_ATTR0_CU_LINK_AURA)
                {
                    if (const std::vector<int32> *spell_triggered = sSpellMgr->GetSpellLinked(GetId() + SPELL_LINK_AURA))
                        for (std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
                        {
                            if (*itr < 0)
                                target->ApplySpellImmune(GetId(), IMMUNITY_ID, -(*itr), false);
                            else
                                target->RemoveAurasDueToSpell(*itr);
                        }
                }
            }
        }
        switch (GetSpellProto()->SpellFamilyName)
        {
        case SPELLFAMILY_GENERIC:
            switch (GetId())
            {
            case 61987:          // Avenging Wrath
                // Remove the immunity shield marker on Avenging Wrath removal if Forbearance is not present
                if (target->HasAura(61988) && !target->HasAura(25771))
                    target->RemoveAura(61988);
                break;
            case 72368:          // Shared Suffering
            case 72369:
                if (caster)
                {
                    if (AuraEffect* aurEff = GetEffect(0))
                    {
                        int32 remainingDamage = aurEff->GetAmount() * (aurEff->GetTotalTicks() - aurEff->GetTickNumber());
                        if (remainingDamage > 0)
                            caster->CastCustomSpell(caster, 72373, NULL, &remainingDamage, NULL, true);
                    }
                }
                break;
            }
            break;
        case SPELLFAMILY_MAGE:
            switch (GetId())
            {
            case 66:          // Invisibility
                if (removeMode != AURA_REMOVE_BY_EXPIRE)
                    break;
                target->CastSpell(target, 32612, true, NULL, GetEffect(1));
                target->CombatStop();          // Mage: Fix Invisibility
                break;
            case 74396:          // Fingers of Frost
                // Remove the IGNORE_AURASTATE aura
                target->RemoveAurasDueToSpell(44544);
                break;
            case 44401:          //Missile Barrage
            case 48108:          //Hot Streak
            case 57761:          //Fireball!
                if (removeMode != AURA_REMOVE_BY_EXPIRE || aurApp->GetBase()->IsExpired())
                    break;
                if (target->HasAura(70752))          //Item - Mage T10 2P Bonus
                    target->CastSpell(target, 70753, true);
                break;
            default:
                break;
            }
            if (!caster)
                break;
            // Ice barrier - dispel/absorb remove
            if (removeMode == AURA_REMOVE_BY_ENEMY_SPELL && GetSpellProto()->SpellFamilyFlags[1] & 0x1)
            {
                // Shattered Barrier
                if (target->HasAura(44745))
                {
                    caster->CastSpell(target, 55080, true);
                }
                if (target->HasAura(54787))
                {
                    caster->CastSpell(target, 83073, true);
                }
            }
            break;
        case SPELLFAMILY_WARRIOR:
            if (!caster)
                break;
            // Spell Reflection
            if (GetSpellProto()->SpellFamilyFlags[1] & 0x2)
            {
                if (removeMode != AURA_REMOVE_BY_DEFAULT)
                {
                    // Improved Spell Reflection
                    if (caster->GetDummyAuraEffect(SPELLFAMILY_WARRIOR, 1935, 1))
                    {
                        // aura remove - remove auras from all party members
                        std::list<Unit*> PartyMembers;
                        target->GetPartyMembers(PartyMembers);
                        for (std::list<Unit*>::iterator itr = PartyMembers.begin(); itr != PartyMembers.end(); ++itr)
                        {
                            if ((*itr) != target)
                                (*itr)->RemoveAurasWithFamily(SPELLFAMILY_WARRIOR, 0, 0x2, 0, GetCasterGUID());
                        }
                    }
                }
            }
            break;
        case SPELLFAMILY_WARLOCK:
            if (!caster)
                break;
            // Curse of Doom
            if (GetSpellProto()->SpellFamilyFlags[1] & 0x02)
            {
                if (removeMode == AURA_REMOVE_BY_DEATH)
                {
                    if (caster->GetTypeId() == TYPEID_PLAYER && caster->ToPlayer()->isHonorOrXPTarget(target))
                        caster->CastSpell(target, 18662, true, NULL, GetEffect(0));
                }
            }
            // Improved Fear
            else if (GetSpellProto()->SpellFamilyFlags[1] & 0x00000400)
            {
                if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_WARLOCK, 98, 0))
                {
                    uint32 spellId = 0;
                    switch (aurEff->GetId())
                    {
                    case 53759:
                        spellId = 60947;
                        break;
                    case 53754:
                        spellId = 60946;
                        break;
                    default:
                        sLog->outError("Aura::HandleAuraSpecificMods: Unknown rank of Improved Fear (%d) found", aurEff->GetId());
                    }
                    if (spellId)
                        caster->CastSpell(target, spellId, true);
                }
            }
            switch (GetId())
            {
            case 6358:          // Seduction
                // Interrupt cast if aura removed from target
                // maybe should be used SpellChannelInterruptFlags instead
                caster->InterruptNonMeleeSpells(false, 6358, false);
                break;
            case 48018:          // Demonic Circle
                // Do not remove GO when aura is removed by stack
                // to prevent remove GO added by new spell
                // old one is already removed
                if (target->HasAura(48018))
                    target->RemoveGameObject(GetId(), true);
                target->RemoveAura(48018);
                break;
            default:
                break;
            }
            break;
        case SPELLFAMILY_PRIEST:
            if (!caster)
                break;
            // Shadow word: Pain // Vampiric Touch
            if (removeMode == AURA_REMOVE_BY_ENEMY_SPELL && (GetSpellProto()->SpellFamilyFlags[0] & 0x00008000 || GetSpellProto()->SpellFamilyFlags[1] & 0x00000400))
            {
                // Shadow Affinity
                if (AuraEffect const * aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 178, 1))
                {
                    int32 basepoints0 = aurEff->GetAmount() * caster->GetCreateMana() / 100;
                    caster->CastCustomSpell(caster, 64103, &basepoints0, NULL, NULL, true, NULL, GetEffect(0));
                }
            }
            // Power word: shield
            else if (removeMode == AURA_REMOVE_BY_ENEMY_SPELL && GetSpellProto()->SpellFamilyFlags[0] & 0x00000001)
            {
                // Rapture
                if (Aura const * aura = caster->GetAuraOfRankedSpell(47535))
                {
                    // check cooldown
                    if (caster->GetTypeId() == TYPEID_PLAYER)
                    {
                        if (caster->ToPlayer()->HasSpellCooldown(aura->GetId()))
                            break;
                        // and add if needed
                        caster->ToPlayer()->AddSpellCooldown(aura->GetId(), 0, uint32(time(NULL) + 12));
                    }
                    // effect on caster
                    if (AuraEffect const * aurEff = aura->GetEffect(0))
                    {
                        float multiplier = (float) aurEff->GetAmount();
                        if (aurEff->GetId() == 47535)
                            multiplier -= 0.5f;
                        else if (aurEff->GetId() == 47537)
                            multiplier += 0.5f;

                        int32 basepoints0 = int32(multiplier * caster->GetMaxPower(POWER_MANA) / 100);
                        caster->CastCustomSpell(caster, 47755, &basepoints0, NULL, NULL, true);
                    }
                    // effect on aura target
                    if (AuraEffect const * aurEff = aura->GetEffect(1))
                    {
                        if (!roll_chance_i(aurEff->GetAmount()))
                            break;

                        int32 triggeredSpellId = 0;
                        switch (target->getPowerType())
                        {
                        case POWER_MANA:
                        {
                            int32 basepoints0 = 2 * (target->GetMaxPower(POWER_MANA) / 100);
                            caster->CastCustomSpell(target, 63654, &basepoints0, NULL, NULL, true);
                            break;
                        }
                        case POWER_RAGE:
                            triggeredSpellId = 63653;
                            break;
                        case POWER_ENERGY:
                            triggeredSpellId = 63655;
                            break;
                        case POWER_RUNIC_POWER:
                            triggeredSpellId = 63652;
                            break;
                        default:
                            break;
                        }
                        if (triggeredSpellId)
                            caster->CastSpell(target, triggeredSpellId, true);
                    }
                }
            }
            switch (GetId())
            {
            case 47788:          // Guardian Spirit
                if (removeMode != AURA_REMOVE_BY_EXPIRE)
                    break;
                if (caster->GetTypeId() != TYPEID_PLAYER)
                    break;

                Player *player = caster->ToPlayer();
                // Glyph of Guardian Spirit
                if (AuraEffect * aurEff = player->GetAuraEffect(63231, 0))
                {
                    if (!player->HasSpellCooldown(47788))
                        break;

                    player->RemoveSpellCooldown(GetSpellProto()->Id, true);
                    player->AddSpellCooldown(GetSpellProto()->Id, 0, uint32(time(NULL) + aurEff->GetAmount()));

                    WorldPacket data(SMSG_SPELL_COOLDOWN, 8 + 1 + 4 + 4);
                    data << uint64(player->GetGUID());
                    data << uint8(0x0);          // flags (0x1, 0x2)
                    data << uint32(GetSpellProto()->Id);
                    data << uint32(aurEff->GetAmount() * IN_MILLISECONDS);
                    player->SendDirectMessage(&data);
                }
                break;
            }
            break;
        case SPELLFAMILY_ROGUE:
            // Remove Vanish on stealth remove
            if (GetId() == 1784)
                target->RemoveAurasWithFamily(SPELLFAMILY_ROGUE, 0x0000800, 0, 0, target->GetGUID());
            else if (GetId() == 6770)          // On-sap removal - blackjack talent
            {
                if (caster->HasAura(79125))          // rank 2
                    caster->CastSpell(target, 79126, true);
                else if (caster->HasAura(79123))          // rank 1
                    caster->CastSpell(target, 79124, true);
            }
            break;
        case SPELLFAMILY_PALADIN:
            // Remove the immunity shield marker on Forbearance removal if AW marker is not present
            if (GetId() == 25771 && target->HasAura(61988) && !target->HasAura(61987))
                target->RemoveAura(61988);
            break;
        case SPELLFAMILY_DEATHKNIGHT:
            // Blood of the North
            // Reaping
            // Death Rune Mastery
            if (GetSpellProto()->SpellIconID == 3041 || GetSpellProto()->SpellIconID == 22 || GetSpellProto()->SpellIconID == 2622)
            {
                if (!GetEffect(0) || GetEffect(0)->GetAuraType() != SPELL_AURA_PERIODIC_DUMMY)
                    break;
                if (target->GetTypeId() != TYPEID_PLAYER)
                    break;
                if (target->ToPlayer()->getClass() != CLASS_DEATH_KNIGHT)
                    break;

                // aura removed - remove death runes
                target->ToPlayer()->RemoveRunesByAuraEffect(GetEffect(0));
            }
            switch (GetId())
            {
            case 50514:          // Summon Gargoyle
                if (removeMode != AURA_REMOVE_BY_EXPIRE)
                    break;
                target->CastSpell(target, GetEffect(0)->GetAmount(), true, NULL, GetEffect(0));
                break;
            }
            break;
        case SPELLFAMILY_HUNTER:
            // Wyvern Sting
            if (removeMode != AURA_REMOVE_BY_STACK && removeMode != AURA_REMOVE_BY_DEATH && GetSpellProto()->SpellFamilyFlags[1] & 0x1000 && caster)
                if (GetId() == 19386)
                    caster->CastSpell(target, 24131, true);

            // Glyph of Freezing Trap
            if (GetSpellProto()->SpellFamilyFlags[0] & 0x00000008)
                if (caster && caster->HasAura(56845))
                    target->CastSpell(target, 61394, true);
            break;
        }
    }

    // mods at aura apply or remove
    switch (GetSpellProto()->SpellFamilyName)
    {
    case SPELLFAMILY_GENERIC:
        switch (GetId())
        {
        case 50720:          // Vigilance
            if (apply)
                target->CastSpell(caster, 59665, true, 0, 0, caster->GetGUID());
            else
                target->SetReducedThreatPercent(0, 0);
            break;
        }
        break;
    case SPELLFAMILY_DRUID:
        // Tiger's Fury
        if (GetSpellProto()->SpellFamilyFlags[2] & 0x800)
        {
            //King of the Jungle
            if (apply)
                if (AuraEffect const * aurEff = target->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_DRUID, 2850, 1))
                {
                    int32 basepoints0 = aurEff->GetAmount();
                    target->CastCustomSpell(target, 51178, &basepoints0, NULL, NULL, true, NULL, NULL, target->GetGUID());
                }
         }
        // Enrage
        if (GetSpellProto()->SpellFamilyFlags[0] & 0x80000)
        {
            //King of the Jungle
            if (apply)
                if (AuraEffect const * aurEff = target->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_DRUID, 2850, 0))
                {
                    int32 basepoints0 = aurEff->GetAmount();
                    target->CastCustomSpell(target, 51185, &basepoints0, NULL, NULL, true, NULL, NULL, target->GetGUID());
                }

            if (target->HasAura(70726))          // Druid T10 Feral 4P Bonus
            {
                if (apply)
                    target->CastSpell(target, 70725, true);
            }
            else          // armor reduction implemented here
            if (AuraEffect * auraEff = target->GetAuraEffectOfRankedSpell(1178, 0))
            {
                int32 value = auraEff->GetAmount();
                int32 mod;
                switch (auraEff->GetId())
                {
                case 1178:
                    mod = 27;
                    break;
                case 9635:
                    mod = 16;
                    break;
                }
                mod = value / 100 * mod;
                value = value + (apply ? -mod : mod);
                auraEff->ChangeAmount(value);
            }
            break;
        }
        break;
    case SPELLFAMILY_ROGUE:
        // Stealth
        if (GetSpellProto()->SpellFamilyFlags[0] & 0x00400000)
        {
            // Master of subtlety
            if (AuraEffect const * aurEff = target->GetAuraEffect(31223, 0))
            {
                if (!apply)
                    target->CastSpell(target, 31666, true);
                else
                {
                    int32 basepoints0 = aurEff->GetAmount();
                    target->CastCustomSpell(target, 31665, &basepoints0, NULL, NULL, true);
                }
            }
            // Overkill
            if (target->HasAura(58426))
            {
                if (!apply)
                    target->CastSpell(target, 58428, true);
                else
                    target->CastSpell(target, 58427, true);
            }
            break;
        }
        break;
    case SPELLFAMILY_HUNTER:
        switch (GetId())
        {
        case 19574:          // Bestial Wrath
            // The Beast Within cast on owner if talent present
            if (Unit* owner = target->GetOwner())
            {
                // Search talent
                if (owner->HasAura(34692))
                {
                    if (apply)
                        owner->CastSpell(owner, 34471, true, 0, GetEffect(0));
                    else
                        owner->RemoveAurasDueToSpell(34471);
                }
            }
            break;
        }
        break;
    case SPELLFAMILY_PALADIN:
        switch (GetId())
        {
        case 19746:
        case 31821:
            // Aura Mastery Triggered Spell Handler
            // If apply Concentration Aura -> trigger -> apply Aura Mastery Immunity
            // If remove Concentration Aura -> trigger -> remove Aura Mastery Immunity
            // If remove Aura Mastery -> trigger -> remove Aura Mastery Immunity
            // Do effects only on aura owner
            if (GetCasterGUID() != target->GetGUID())
                break;
            if (apply)
            {
                if ((GetSpellProto()->Id == 31821 && target->HasAura(19746, GetCasterGUID())) || (GetSpellProto()->Id == 19746 && target->HasAura(31821)))
                    target->CastSpell(target, 64364, true);
            }
            else
                target->RemoveAurasDueToSpell(64364, GetCasterGUID());
            break;
        }
        break;
    case SPELLFAMILY_DEATHKNIGHT:
        if (GetSpellSpecific(GetSpellProto()) == SPELL_SPECIFIC_PRESENCE)
        {
            caster->SetPower(POWER_RUNIC_POWER, 0);
            AuraEffect *bloodPresenceAura = 0;          // healing by damage done
            AuraEffect *frostPresenceAura = 0;          // increased health
            AuraEffect *unholyPresenceAura = 0;          // increased movement speed, faster rune recovery

            // Improved Presences
            Unit::AuraEffectList const& vDummyAuras = target->GetAuraEffectsByType(SPELL_AURA_DUMMY);
            for (Unit::AuraEffectList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr)
            {
                switch ((*itr)->GetId())
                {
                // Improved Blood Presence
                case 50365:
                case 50371:
                {
                    bloodPresenceAura = (*itr);
                    break;
                }
                    // Improved Frost Presence
                case 50384:
                case 50385:
                {
                    frostPresenceAura = (*itr);
                    break;
                }
                    // Improved Unholy Presence
                case 50391:
                case 50392:
                {
                    unholyPresenceAura = (*itr);
                    break;
                }
                }
            }

            uint32 presence = GetId();
            if (apply)
            {
                // Blood Presence bonus
                if (presence == 48263)
                    target->CastSpell(target, 61261, true);
                else if (bloodPresenceAura)
                {
                    int32 basePoints1 = bloodPresenceAura->GetAmount();
                    target->CastCustomSpell(target, 61261, NULL, &basePoints1, NULL, true, 0, bloodPresenceAura);
                }
                // Frost Presence bonus
                if (presence == 48266)
                    target->CastSpell(target, 63611, true);
                else if (frostPresenceAura)
                {
                    int32 basePoints0 = frostPresenceAura->GetAmount();
                    target->CastCustomSpell(target, 63611, &basePoints0, NULL, NULL, true, 0, frostPresenceAura);
                }
                // Unholy Presence bonus
                if (presence == 48265)
					target->CastSpell(target, 63622, true);
                else if (unholyPresenceAura)
                {
                    int32 basePoints0 = unholyPresenceAura->GetAmount();
                    target->CastCustomSpell(target, 63622, &basePoints0, NULL, NULL, true, 0, unholyPresenceAura);
                }
            }
            else
            {
                // Remove passive auras
                if (presence == 48266 || bloodPresenceAura)
                    target->RemoveAurasDueToSpell(63611);
                if (presence == 48263 || frostPresenceAura)
                    target->RemoveAurasDueToSpell(61261);
                if (presence == 48265 || unholyPresenceAura)
					target->RemoveAurasDueToSpell(63622);
            }
        }
        break;
    }
}

bool Aura::CanBeAppliedOn (Unit *target)
{
    // unit not in world or during remove from world
    if (!target->IsInWorld() || target->IsDuringRemoveFromWorld())
    {
        // area auras mustn't be applied
        if (GetOwner() != target)
            return false;
        // not selfcasted single target auras mustn't be applied
        if (GetCasterGUID() != GetOwner()->GetGUID() && IsSingleTargetSpell(GetSpellProto()))
            return false;
    }
    else if (GetOwner() != target)
        return CheckAreaTarget(target);
    return true;
}

bool Aura::CheckAreaTarget (Unit *target)
{
    // for owner check use Spell::CheckTarget
    ASSERT(GetOwner() != target);

    // some special cases
    switch (GetId())
    {
    case 45828:          // AV Marshal's HP/DMG auras
    case 45829:
    case 45830:
    case 45821:
    case 45822:          // AV Warmaster's HP/DMG auras
    case 45823:
    case 45824:
    case 45826:
        switch (target->GetEntry())
        {
        // alliance
        case 14762:          // Dun Baldar North Marshal
        case 14763:          // Dun Baldar South Marshal
        case 14764:          // Icewing Marshal
        case 14765:          // Stonehearth Marshal
        case 11948:          // Vandar Stormspike
            // horde
        case 14772:          // East Frostwolf Warmaster
        case 14776:          // Tower Point Warmaster
        case 14773:          // Iceblood Warmaster
        case 14777:          // West Frostwolf Warmaster
        case 11946:          // Drek'thar
            return true;
        default:
            return false;
            break;
        }
        break;
    }
    return true;
}

void Aura::_DeleteRemovedApplications ()
{
    while (!m_removedApplications.empty())
    {
        delete m_removedApplications.front();
        m_removedApplications.pop_front();
    }
}

void Aura::LoadScripts ()
{
    sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Aura::LoadScripts");
    sScriptMgr->CreateAuraScripts(m_spellProto->Id, m_loadedScripts);
    for (std::list<AuraScript *>::iterator itr = m_loadedScripts.begin(); itr != m_loadedScripts.end();)
    {
        if (!(*itr)->_Load(this))
        {
            std::list<AuraScript *>::iterator bitr = itr;
            ++itr;
            m_loadedScripts.erase(bitr);
            continue;
        }
        (*itr)->Register();
        ++itr;
    }
}

bool Aura::CallScriptEffectApplyHandlers (AuraEffect const * aurEff, AuraApplication const * aurApp, AuraEffectHandleModes mode)
{
    bool preventDefault = false;
    for (std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
    {
        (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_APPLY, aurApp);
        std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectApply.end(), effItr = (*scritr)->OnEffectApply.begin();
        for (; effItr != effEndItr; ++effItr)
        {
            if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex()))
                (*effItr).Call(*scritr, aurEff, mode);
        }
        if (!preventDefault)
            preventDefault = (*scritr)->_IsDefaultActionPrevented();
        (*scritr)->_FinishScriptCall();
    }
    return preventDefault;
}

bool Aura::CallScriptEffectRemoveHandlers (AuraEffect const * aurEff, AuraApplication const * aurApp, AuraEffectHandleModes mode)
{
    bool preventDefault = false;
    for (std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
    {
        (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_REMOVE, aurApp);
        std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectRemove.end(), effItr = (*scritr)->OnEffectRemove.begin();
        for (; effItr != effEndItr; ++effItr)
        {
            if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex()))
                (*effItr).Call(*scritr, aurEff, mode);
        }
        if (!preventDefault)
            preventDefault = (*scritr)->_IsDefaultActionPrevented();
        (*scritr)->_FinishScriptCall();
    }
    return preventDefault;
}

bool Aura::CallScriptEffectPeriodicHandlers (AuraEffect const * aurEff, AuraApplication const * aurApp)
{
    bool preventDefault = false;
    for (std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
    {
        (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_PERIODIC, aurApp);
        std::list<AuraScript::EffectPeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectPeriodic.end(), effItr = (*scritr)->OnEffectPeriodic.begin();
        for (; effItr != effEndItr; ++effItr)
        {
            if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex()))
                (*effItr).Call(*scritr, aurEff);
        }
        if (!preventDefault)
            preventDefault = (*scritr)->_IsDefaultActionPrevented();
        (*scritr)->_FinishScriptCall();
    }
    return preventDefault;
}

void Aura::CallScriptEffectUpdatePeriodicHandlers (AuraEffect * aurEff)
{
    for (std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
    {
        (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_UPDATE_PERIODIC);
        std::list<AuraScript::EffectUpdatePeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectUpdatePeriodic.end(), effItr = (*scritr)->OnEffectUpdatePeriodic.begin();
        for (; effItr != effEndItr; ++effItr)
        {
            if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex()))
                (*effItr).Call(*scritr, aurEff);
        }
        (*scritr)->_FinishScriptCall();
    }
}

void Aura::CallScriptEffectCalcAmountHandlers (AuraEffect const * aurEff, int32 & amount, bool & canBeRecalculated)
{
    for (std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
    {
        (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_AMOUNT);
        std::list<AuraScript::EffectCalcAmountHandler>::iterator effEndItr = (*scritr)->DoEffectCalcAmount.end(), effItr = (*scritr)->DoEffectCalcAmount.begin();
        for (; effItr != effEndItr; ++effItr)
        {
            if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex()))
                (*effItr).Call(*scritr, aurEff, amount, canBeRecalculated);
        }
        (*scritr)->_FinishScriptCall();
    }
}

void Aura::CallScriptEffectCalcPeriodicHandlers (AuraEffect const * aurEff, bool & isPeriodic, int32 & amplitude)
{
    for (std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
    {
        (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_PERIODIC);
        std::list<AuraScript::EffectCalcPeriodicHandler>::iterator effEndItr = (*scritr)->DoEffectCalcPeriodic.end(), effItr = (*scritr)->DoEffectCalcPeriodic.begin();
        for (; effItr != effEndItr; ++effItr)
        {
            if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex()))
                (*effItr).Call(*scritr, aurEff, isPeriodic, amplitude);
        }
        (*scritr)->_FinishScriptCall();
    }
}

void Aura::CallScriptEffectCalcSpellModHandlers (AuraEffect const * aurEff, SpellModifier *& spellMod)
{
    for (std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
    {
        (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_SPELLMOD);
        std::list<AuraScript::EffectCalcSpellModHandler>::iterator effEndItr = (*scritr)->DoEffectCalcSpellMod.end(), effItr = (*scritr)->DoEffectCalcSpellMod.begin();
        for (; effItr != effEndItr; ++effItr)
        {
            if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex()))
                (*effItr).Call(*scritr, aurEff, spellMod);
        }
        (*scritr)->_FinishScriptCall();
    }
}

void Aura::CallScriptEffectAbsorbHandlers (AuraEffect * aurEff, AuraApplication const * aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount, bool & defaultPrevented)
{
    for (std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
    {
        (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_ABSORB, aurApp);
        std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->OnEffectAbsorb.end(), effItr = (*scritr)->OnEffectAbsorb.begin();
        for (; effItr != effEndItr; ++effItr)
        {
            if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex()))
                (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
        }
        if (!defaultPrevented)
            defaultPrevented = (*scritr)->_IsDefaultActionPrevented();
        (*scritr)->_FinishScriptCall();
    }
}

void Aura::CallScriptEffectAfterAbsorbHandlers (AuraEffect * aurEff, AuraApplication const * aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount)
{
    for (std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
    {
        (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_ABSORB, aurApp);
        std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->AfterEffectAbsorb.end(), effItr = (*scritr)->AfterEffectAbsorb.begin();
        for (; effItr != effEndItr; ++effItr)
        {
            if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex()))
                (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
        }
        (*scritr)->_FinishScriptCall();
    }
}

void Aura::CallScriptEffectManaShieldHandlers (AuraEffect * aurEff, AuraApplication const * aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount, bool & defaultPrevented)
{
    for (std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
    {
        (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_MANASHIELD, aurApp);
        std::list<AuraScript::EffectManaShieldHandler>::iterator effEndItr = (*scritr)->OnEffectManaShield.end(), effItr = (*scritr)->OnEffectManaShield.begin();
        for (; effItr != effEndItr; ++effItr)
        {
            if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex()))
                (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
        }
        if (!defaultPrevented)
            defaultPrevented = (*scritr)->_IsDefaultActionPrevented();
        (*scritr)->_FinishScriptCall();
    }
}

void Aura::CallScriptEffectAfterManaShieldHandlers (AuraEffect * aurEff, AuraApplication const * aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount)
{
    for (std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
    {
        (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD, aurApp);
        std::list<AuraScript::EffectManaShieldHandler>::iterator effEndItr = (*scritr)->AfterEffectManaShield.end(), effItr = (*scritr)->AfterEffectManaShield.begin();
        for (; effItr != effEndItr; ++effItr)
        {
            if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex()))
                (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
        }
        (*scritr)->_FinishScriptCall();
    }
}

UnitAura::UnitAura (SpellEntry const* spellproto, uint8 effMask, WorldObject * owner, Unit * caster, int32 *baseAmount, Item * castItem, uint64 casterGUID) :
        Aura(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID)
{
    m_AuraDRGroup = DIMINISHING_NONE;
    LoadScripts();
    _InitEffects(effMask, caster, baseAmount);
    GetUnitOwner()->_AddAura(this, caster);
    if (GetUnitOwner()->GetTypeId() == TYPEID_PLAYER)
        sScriptMgr->OnPlayerAura(GetUnitOwner()->ToPlayer(), spellproto);
}
;

void UnitAura::_ApplyForTarget (Unit * target, Unit * caster, AuraApplication * aurApp)
{
    Aura::_ApplyForTarget(target, caster, aurApp);

    // register aura diminishing on apply
    if (DiminishingGroup group = GetDiminishGroup())
        target->ApplyDiminishingAura(group, true);
}

void UnitAura::_UnapplyForTarget (Unit * target, Unit * caster, AuraApplication * aurApp)
{
    Aura::_UnapplyForTarget(target, caster, aurApp);

    // unregister aura diminishing (and store last time)
    if (DiminishingGroup group = GetDiminishGroup())
        target->ApplyDiminishingAura(group, false);
}

void UnitAura::Remove (AuraRemoveMode removeMode)
{
    if (IsRemoved())
        return;
    GetUnitOwner()->RemoveOwnedAura(this, removeMode);
}

void UnitAura::FillTargetMap (std::map<Unit *, uint8> & targets, Unit * caster)
{
    Player * modOwner = NULL;
    if (caster)
        modOwner = caster->GetSpellModOwner();

    for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
    {
        if (!HasEffect(effIndex))
            continue;
        UnitList targetList;
        // non-area aura
        if (GetSpellProto()->Effect[effIndex] == SPELL_EFFECT_APPLY_AURA)
        {
            targetList.push_back(GetUnitOwner());
        }
        else
        {
            float radius;
            if (GetSpellProto()->Effect[effIndex] == SPELL_EFFECT_APPLY_AREA_AURA_ENEMY)
                radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(GetSpellProto()->EffectRadiusIndex[effIndex]));
            else
                radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(GetSpellProto()->EffectRadiusIndex[effIndex]));

            if (modOwner)
                modOwner->ApplySpellMod(GetId(), SPELLMOD_RADIUS, radius);

            if (!GetUnitOwner()->HasUnitState(UNIT_STAT_ISOLATED))
            {
                switch (GetSpellProto()->Effect[effIndex])
                {
                case SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
                    targetList.push_back(GetUnitOwner());
                    GetUnitOwner()->GetPartyMemberInDist(targetList, radius);
                    break;
                case SPELL_EFFECT_APPLY_AREA_AURA_RAID:
                    targetList.push_back(GetUnitOwner());
                    GetUnitOwner()->GetRaidMember(targetList, radius);
                    if (GetSpellProto()->SpellIconID == 691)
                        GetUnitOwner()->GetRaidMember(targetList, GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(GetSpellProto()->EffectRadiusIndex[1])));
                    break;
                case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
                {
                    targetList.push_back(GetUnitOwner());
                    Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius);
                    Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(GetUnitOwner(), targetList, u_check);
                    GetUnitOwner()->VisitNearbyObject(radius, searcher);
                    break;
                }
                case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY:
                {
                    Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius);          // No GetCharmer in searcher
                    Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(GetUnitOwner(), targetList, u_check);
                    GetUnitOwner()->VisitNearbyObject(radius, searcher);
                    break;
                }
                case SPELL_EFFECT_APPLY_AREA_AURA_PET:
                    targetList.push_back(GetUnitOwner());
                case SPELL_EFFECT_APPLY_AREA_AURA_OWNER:
                {
                    if (Unit *owner = GetUnitOwner()->GetCharmerOrOwner())
                        if (GetUnitOwner()->IsWithinDistInMap(owner, radius))
                            targetList.push_back(owner);
                    break;
                }
                }
            }
        }

        for (UnitList::iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
        {
            std::map<Unit *, uint8>::iterator existing = targets.find(*itr);
            if (existing != targets.end())
                existing->second |= 1 << effIndex;
            else
                targets[*itr] = 1 << effIndex;
        }
    }
}

DynObjAura::DynObjAura (SpellEntry const* spellproto, uint8 effMask, WorldObject * owner, Unit * caster, int32 *baseAmount, Item * castItem, uint64 casterGUID) :
        Aura(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID)
{
    LoadScripts();
    ASSERT(GetDynobjOwner());
    ASSERT(GetDynobjOwner()->IsInWorld());
    ASSERT(GetDynobjOwner()->GetMap() == caster->GetMap());
    _InitEffects(effMask, caster, baseAmount);
    GetDynobjOwner()->SetAura(this);
}

void DynObjAura::Remove (AuraRemoveMode removeMode)
{
    if (IsRemoved())
        return;
    _Remove(removeMode);
}

void DynObjAura::FillTargetMap (std::map<Unit *, uint8> & targets, Unit * /*caster*/)
{
    Unit * dynObjOwnerCaster = GetDynobjOwner()->GetCaster();
    float radius = GetDynobjOwner()->GetRadius();

    for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
    {
        if (!HasEffect(effIndex))
            continue;
        UnitList targetList;
        if (GetSpellProto()->EffectImplicitTargetB[effIndex] == TARGET_DEST_DYNOBJ_ALLY || GetSpellProto()->EffectImplicitTargetB[effIndex] == TARGET_UNIT_AREA_ALLY_DST)
        {
            Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
            Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check);
            GetDynobjOwner()->VisitNearbyObject(radius, searcher);
        }
        else if (GetSpellProto()->EffectImplicitTargetB[effIndex] == TARGET_DEST_DYNOBJ_ALL_UNITS)
        {
            Trinity::AnyUnitInObjectRangeCheck u_check(GetDynobjOwner(), radius);
            Trinity::UnitListSearcher<Trinity::AnyUnitInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check);
            GetDynobjOwner()->VisitNearbyObject(radius, searcher);
        }
        else
        {
            Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
            Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check);
            GetDynobjOwner()->VisitNearbyObject(radius, searcher);
        }

        for (UnitList::iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
        {
            std::map<Unit *, uint8>::iterator existing = targets.find(*itr);
            if (existing != targets.end())
                existing->second |= 1 << effIndex;
            else
                targets[*itr] = 1 << effIndex;
        }
    }
}
